package com.lonwin.mes2u8.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.lonwin.mes2u8.domain.mes.MesBatchCodeInfo;
import com.lonwin.mes2u8.domain.mes.MesProductionQueryResult;
import com.lonwin.mes2u8.domain.u8.*;
import com.lonwin.mes2u8.service.BatchCodeService;
import com.lonwin.mes2u8.service.InventoryAppService;
import com.lonwin.mes2u8.service.ProductionAppService;
import com.lonwin.mes2u8.util.MyQueueUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
import java.util.stream.Collectors;

/**
 * 成品入库单相关操作
 *
 * @author DELL
 * @Date 2023-12-18 10:51
 */
@Controller
@RequestMapping("/production")
@ResponseBody
@Slf4j
public class ProductionController {

    @Resource
    private BatchCodeService batchCodeService;
    @Resource
    private InventoryAppService inventoryAppService;
    @Resource
    private ProductionAppService productionAppService;

    @GetMapping("/add")
    // public String addProductions(@RequestParam String start, @RequestParam String end) {
    public String addProductions() {
        log.info("ProductionController addProductions  start");
        // 从MES获取批次列表
        log.info("ProductionController addProductions 1 get Production list");
        List<MesBatchCodeInfo> mesBatchCodeInfoList = batchCodeService.queryMesBatchList();

        if (mesBatchCodeInfoList.isEmpty()) {
            log.info("ProductionController addProductions result 1 : query 0 , add 0");
            return "";
        }

        List<String> batchCodeList = mesBatchCodeInfoList.stream().map(MesBatchCodeInfo::getBno)
        // CommonValue.hisBatchList.contains(s) ||
                .filter(s -> (!s.startsWith("22") && !s.startsWith("23")))
                .collect(Collectors.toList());
        log.info("ProductionController addProductions 2 start handler Production list");
        return addProductions(batchCodeList);
    }
    @GetMapping("/test")
    // public String addProductions(@RequestParam String start, @RequestParam String end) {
    public String addProductionsTest() {
        log.info("ProductionController addProductions  start");
        // 从MES获取批次列表
        log.info("ProductionController addProductions 1 get Production list");
        List<MesBatchCodeInfo> mesBatchCodeInfoList = batchCodeService.queryMesBatchList();

        if (mesBatchCodeInfoList.isEmpty()) {
            log.info("ProductionController addProductions result 1 : query 0 , add 0");
            return "";
        }

        List<String> batchCodeList = mesBatchCodeInfoList.stream().map(MesBatchCodeInfo::getBno)
                // CommonValue.hisBatchList.contains(s) ||
                .filter(s -> (!s.startsWith("22") && !s.startsWith("23")))
                .collect(Collectors.toList());
        log.info("ProductionController addProductions 2 start handler Production list");
//        List<String> batchCodeList = Lists.newArrayList("24207");
        return addProductionsTest(batchCodeList);
    }

    /*
     * 1. MES中按批次号查询可以得到这个批次号下所有成品入单库记录
     * 2. 使用批次号去U8中查询成品入库单
     * 3. 将MES中获取到的数量减去U8中现在的数量即为待入库的数量
     * 4. 判断存货是否存在，如果不存在则添加
     * 5. 将其转换为U8的导入参数
     * 6. 导入出库单，再进行下一个成品编码的查询，到第2步
     */
    public String addProductions(List<String> batchCodeList) {
        Queue<DefineSyncResponse> failedQueue = Lists.newLinkedList();
        Queue<DefineSyncResponse> checkQueue = Lists.newLinkedList();
        // 从U8中查找指定批次号的材料出库单
        for (int i = 0 ; i < batchCodeList.size() ; i++) {
            String batchCode = batchCodeList.get(i);
            log.info("ProductionController addProductions 3 start : total {}, now {} --- {}",  batchCodeList.size(), i+1, batchCode);
            // 查找mes成品入库单
            List<MesProductionQueryResult> mesProductionInfo = productionAppService.getMesProductionInfo(batchCode);

            // 将MES成品入库单按照 成品编号 进行分组, 每一项都包含了当前批次、成品编号、实际使用了的物料编号、数量
            U8ProductionHandlerResult mesLastProductionResult = productionAppService.handleMesProductionQueryResultOfGroup(mesProductionInfo);

            if (Objects.isNull(mesLastProductionResult) || Objects.isNull(mesLastProductionResult.getInfoList()) || mesLastProductionResult.getInfoList().isEmpty()) {
                // mes中成品入库单中没有内容，则不需要录入
                log.info("ProductionController addProductions 3.2 get for U8 is new : {}", batchCode);
                continue;
            }

            // 查看存货是否存在
            for (U8ProductionHandlerResultInfo mesInfo : mesLastProductionResult.getInfoList()) {
                // 按 产品编号 查找U8存货，如果不存在则添加
                U8CommonSyncResponse u8CommonSyncResponse = inventoryAppService.addInventoryOfU8IfNotExist(mesInfo.getInventorycode());

                if (Objects.nonNull(u8CommonSyncResponse)) {
                    DefineSyncResponse defineSyncResponse = DefineSyncResponse.buildSelfBySyncResponse(u8CommonSyncResponse, mesInfo.getInventorycode(), MyObjTypeEnum.INVENTORY);
                    checkQueue.add(defineSyncResponse);
                }
            }

            Queue<DefineSyncResponse> inventoryFailedQueue = MyQueueUtil.checkQueueSuccess(checkQueue);
            if (!inventoryFailedQueue.isEmpty()) {
                failedQueue.addAll(inventoryFailedQueue);
                log.info("ProductionController addProductions 3.3 add inventory failed : {}", inventoryFailedQueue.size());
                // 存货未录入成功，跳过当前产品入库单录入
                continue;
            }

            // 查看成品入库单是否存在
            // 查看成口入库单列表
            List<U8ProductionBatchGetResultInfo> u8ProductionBatchGetInfos = productionAppService.findU8ProductionInfoByBatchCode(batchCode);

            U8ProductionHandlerResult u8LastProductionResult = null;
            if (Objects.nonNull(u8ProductionBatchGetInfos) && !u8ProductionBatchGetInfos.isEmpty()) {
                u8LastProductionResult = productionAppService.handleU8ProductionQueryResultEntryList(batchCode, u8ProductionBatchGetInfos);
            }


            // 对MES成品入库单和U8成品入库单进行处理，生成待录入的结果
            log.info("ProductionController addMaterial {} : mesLastProductionResult : {}", i, JSON.toJSONString(mesLastProductionResult));
            log.info("ProductionController addMaterial {} : u8LastProductionResult : {}", i, JSON.toJSONString(u8LastProductionResult));
            U8ProductionHandlerResult handleredCanRecord = handlerCanRecord(mesLastProductionResult, u8LastProductionResult);

            U8ProductionAddParam addParam = handleredCanRecord.convertU8ProductionAddParam();

            if (Objects.nonNull(addParam) && !addParam.getProductin().getEntry().isEmpty()) {
                U8CommonSyncResponse u8CommonSyncResponse = productionAppService.addProductionToU8(addParam);

                DefineSyncResponse addProductionResult = DefineSyncResponse.buildSelfBySyncResponse(u8CommonSyncResponse, batchCode, MyObjTypeEnum.PRODUCTION);

                DefineSyncResponse responseSuccess = MyQueueUtil.isResponseSuccess(addProductionResult);

                if (Objects.nonNull(responseSuccess)) {
                    failedQueue.add(responseSuccess);
                }
            }

        }

        if(!failedQueue.isEmpty()) {
            log.error("MaterialOutController.addMaterial record failed : {}", failedQueue.size());
            log.error("MaterialOutController.addMaterial record failed info:");
            failedQueue.forEach(
                    res -> log.error("add {} failed : {} -- {}", res.getType().getName(),  res.getCode(), res.getMessage())
            );
        }

        log.info("ProductionController addProductions end");
        return "";

    }


    public String addProductionsTest(List<String> batchCodeList) {
        /*
         * 1. MES中按批次号查询可以得到这个批次号下所有成品入单库记录
         * 2. 使用批次号去U8中查询成品入库单
         * 3. 将MES中获取到的数量减去U8中现在的数量即为待入库的数量
         * 4. 判断存货是否存在，如果不存在则添加
         * 5. 将其转换为U8的导入参数
         * 6. 导入出库单，再进行下一个成品编码的查询，到第2步
         */
        Queue<DefineSyncResponse> failedQueue = Lists.newLinkedList();
        Queue<DefineSyncResponse> checkQueue = Lists.newLinkedList();
        // 从U8中查找指定批次号的材料出库单
        for (int i = 0; i < batchCodeList.size(); i++) {
            String batchCode = batchCodeList.get(i);
            log.info("ProductionController addProductions 3 start : total {}, now {} --- {}", batchCodeList.size(), i + 1, batchCode);
            // 查找mes成品入库单
            List<MesProductionQueryResult> mesProductionInfo = productionAppService.getMesProductionInfo(batchCode);

            // 将MES成品入库单按照 成品编号 进行分组, 每一项都包含了当前批次、成品编号、实际使用了的物料编号、数量
            U8ProductionHandlerResult mesLastProductionResult = productionAppService.handleMesProductionQueryResultOfGroup(mesProductionInfo);

            if (Objects.isNull(mesLastProductionResult) || Objects.isNull(mesLastProductionResult.getInfoList()) || mesLastProductionResult.getInfoList().isEmpty()) {
                // mes中成品入库单中没有内容，则不需要录入
                log.info("ProductionController addProductions 3.2 get for U8 is new : {}", batchCode);
                continue;
            }

            // 查看存货是否存在
            for (U8ProductionHandlerResultInfo mesInfo : mesLastProductionResult.getInfoList()) {
                // 按 产品编号 查找U8存货，如果不存在则添加
                U8CommonSyncResponse u8CommonSyncResponse = inventoryAppService.addInventoryOfU8IfNotExist(mesInfo.getInventorycode());

                if (Objects.nonNull(u8CommonSyncResponse)) {
                    DefineSyncResponse defineSyncResponse = DefineSyncResponse.buildSelfBySyncResponse(u8CommonSyncResponse, mesInfo.getInventorycode(), MyObjTypeEnum.INVENTORY);
                    checkQueue.add(defineSyncResponse);
                }
            }

            Queue<DefineSyncResponse> inventoryFailedQueue = MyQueueUtil.checkQueueSuccess(checkQueue);
            if (!inventoryFailedQueue.isEmpty()) {
                failedQueue.addAll(inventoryFailedQueue);
                log.info("ProductionController addProductions 3.3 add inventory failed : {}", inventoryFailedQueue.size());
                // 存货未录入成功，跳过当前产品入库单录入
                continue;
            }

            // 查看成品入库单是否存在
            // 查看成口入库单列表
            List<U8ProductionBatchGetResultInfo> u8ProductionBatchGetInfos = productionAppService.findU8ProductionInfoByBatchCode(batchCode);

            U8ProductionHandlerResult u8LastProductionResult = null;
            if (Objects.nonNull(u8ProductionBatchGetInfos) && !u8ProductionBatchGetInfos.isEmpty()) {
                u8LastProductionResult = productionAppService.handleU8ProductionQueryResultEntryList(batchCode, u8ProductionBatchGetInfos);
            }


            // 对MES成品入库单和U8成品入库单进行处理，生成待录入的结果
            log.info("ProductionController addMaterial {} : mesLastProductionResult : {}", i, JSON.toJSONString(mesLastProductionResult));
            log.info("ProductionController addMaterial {} : u8LastProductionResult : {}", i, JSON.toJSONString(u8LastProductionResult));
            U8ProductionHandlerResult handleredCanRecord = handlerCanRecord(mesLastProductionResult, u8LastProductionResult);
            log.info("ProductionController addMaterial {} : handler result : {}", i, JSON.toJSONString(handleredCanRecord));
        }
        return "";
    }

    private U8ProductionHandlerResult handlerCanRecord(U8ProductionHandlerResult mesLastProductionInfo, U8ProductionHandlerResult u8LastProductionInfo) {
        U8ProductionHandlerResult result = new U8ProductionHandlerResult();
        result.setBatchCode(mesLastProductionInfo.getBatchCode());

        if (Objects.isNull(u8LastProductionInfo)) {
            return mesLastProductionInfo;
        }

        List<U8ProductionHandlerResultInfo> resultInfoList = Lists.newArrayList();
        for (U8ProductionHandlerResultInfo mesLastItem : mesLastProductionInfo.getInfoList()) {

            // 筛选U8中与当前MES成品相同的记录
            U8ProductionHandlerResultInfo u8SameToMes = u8LastProductionInfo.getInfoList().stream()
                    .filter(u8LastItem -> u8LastItem.getInventorycode().equals(mesLastItem.getInventorycode().replace("-", "")))
                    .findFirst().orElse(null);

            if (Objects.isNull(u8SameToMes)) {
                resultInfoList.add(mesLastItem);
                continue;
            }

            BigDecimal difQuantity = mesLastItem.getQuantity().subtract(u8SameToMes.getQuantity().multiply(new BigDecimal("1000")));
            BigDecimal difNumber = mesLastItem.getNumber().subtract(u8SameToMes.getNumber()==null?BigDecimal.ZERO:u8SameToMes.getNumber());

            if (difQuantity.compareTo(BigDecimal.ZERO) > 0) {
                U8ProductionHandlerResultInfo tmpInfo = new U8ProductionHandlerResultInfo();
                tmpInfo.setInventorycode(u8SameToMes.getInventorycode());
                tmpInfo.setQuantity(difQuantity);
                tmpInfo.setNumber(difNumber);
                resultInfoList.add(tmpInfo);
            }

        }
        result.setInfoList(resultInfoList);
        return result;
    }
}
